using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using Deepcode.Flux.Core.Data;

namespace Deepcode.Flux.Core.Systems.Security
{
	/// <summary>
	/// The AdministrationUsers collection provides methods to obtain and save
	/// AdministrationUser objects.
	/// </summary>
	public class AdministrationUsers : BaseManager
	{
		#region Constructors
		public AdministrationUsers() : base() { }
		public AdministrationUsers(SqlConnection CurrentConnection) : base(CurrentConnection) { }
		public AdministrationUsers(SqlConnection CurrentConnection, SqlTransaction CurrentTransaction) : base(CurrentConnection, CurrentTransaction) { }
		#endregion
		/// <summary>
		/// Retrieves all administraiton users sorted by ID in ascending order
		/// </summary>
		/// <returns></returns>
		public AdministrationUser[] GetAllUsers()
		{
			return GetAllUsers(AdministrationUsersSortOrder.PK_ID);
		}
		
		
		/// <summary>
		/// Retrieves all administration users sorted by the order specified (ascending order)
		/// </summary>
		/// <param name="order"></param>
		/// <returns></returns>
		public AdministrationUser[] GetAllUsers(AdministrationUsersSortOrder order)
		{
			return GetAllUsers(order, DataSortDirection.ASCENDING);
		}
		
		
		/// <summary>
		/// Retrieves all administration users sorted by the sort order specified, with
		/// the sort direction specified.
		/// </summary>
		/// <param name="order"></param>
		/// <param name="direction"></param>
		/// <returns></returns>
		public AdministrationUser[] GetAllUsers(AdministrationUsersSortOrder order, DataSortDirection direction)
		{
			DataTable results = new DataTable();
			EstablishConnection();
			SqlDataAdapter da = this.CreateDataAdapter("coreAdminUserGetAll");
			da.SelectCommand.Parameters.Add(SQLUtility.ParameterIn("@SortExpression", SqlDbType.NVarChar, 50, order.ToString()));
			da.SelectCommand.Parameters.Add(SQLUtility.ParameterIn("@SortDirection", SqlDbType.Int, 4, (int) direction));
			da.Fill(results);
			ReleaseConnection();

			List<AdministrationUser> list = new List<AdministrationUser>();
			foreach (DataRow r in results.Rows)
				list.Add(new AdministrationUser(r));

			return list.ToArray();
		}

		/// <summary>
		/// Retrieves a list of all users within a particular group
		/// </summary>
		/// <param name="GroupID"></param>
		/// <returns></returns>
		public AdministrationUser[] GetAllUsersInGroup(int GroupID)
		{
			DataTable results = new DataTable();
			EstablishConnection();
			SqlDataAdapter da = this.CreateDataAdapter("coreAdminUserGetAllInGroup");
			da.SelectCommand.Parameters.Add(SQLUtility.ParameterIn("@id", SqlDbType.Int, 4, GroupID));
			da.Fill(results);
			ReleaseConnection();

			List<AdministrationUser> list = new List<AdministrationUser>();
			foreach (DataRow r in results.Rows)
				list.Add(new AdministrationUser(r));

			return list.ToArray();
		}
		
		/// <summary>
		/// Finds and returns an administration user by ID
		/// </summary>
		/// <param name="ID"></param>
		/// <returns></returns>
		public AdministrationUser GetUserByID(int ID)
		{
			DataTable result = new DataTable();

			EstablishConnection();
			SqlDataAdapter da = this.CreateDataAdapter("coreAdminUserGetByID");
			da.SelectCommand.Parameters.Add(SQLUtility.ParameterIn("@id", SqlDbType.Int, 4, ID));
			da.Fill(result);
			ReleaseConnection();

			if (result == null) return null;
			if (result.Rows.Count < 1) return null;

			return new AdministrationUser(result.Rows[0]);
		}
		
		
		/// <summary>
		/// Finds an administration user by email address
		/// </summary>
		/// <param name="EmailAddress"></param>
		/// <returns></returns>
		public AdministrationUser GetUserByEmail(string EmailAddress)
		{
			DataTable result = new DataTable();

			EstablishConnection();
			SqlDataAdapter da = this.CreateDataAdapter("coreAdminUserGetByEmail");
			da.SelectCommand.Parameters.Add(SQLUtility.ParameterIn("@email", SqlDbType.NVarChar, 300, EmailAddress));
			da.Fill(result);
			ReleaseConnection();

			if (result == null) return null;
			if (result.Rows.Count < 1) return null;

			return new AdministrationUser(result.Rows[0]);
		}
		
		
		/// <summary>
		/// Finds an administration user by NT Authentication name
		/// </summary>
		/// <param name="NTName"></param>
		/// <returns></returns>
		public AdministrationUser GetUserByNTName(string NTName)
		{
			DataTable result = new DataTable();

			EstablishConnection();
			SqlDataAdapter da = this.CreateDataAdapter("coreAdminUserGetByNT");
			da.SelectCommand.Parameters.Add(SQLUtility.ParameterIn("@NTName", SqlDbType.NVarChar, 200, NTName));
			da.Fill(result);
			ReleaseConnection();

			if (result == null) return null;
			if (result.Rows.Count < 1) return null;

			return new AdministrationUser(result.Rows[0]);
		}
		
		
		/// <summary>
		/// Finds an administration user by the email and password passed in. (FORMS Auth only)
		/// </summary>
		/// <param name="?"></param>
		/// <param name="?"></param>
		/// <returns></returns>
		public AdministrationUser GetUserByFormCredentials(string email, string password)
		{
			string searchPass = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(password, "sha1");

			DataTable result = new DataTable();

			EstablishConnection();
			SqlDataAdapter da = this.CreateDataAdapter("coreAdminUserGetByFormCredentials");
			da.SelectCommand.Parameters.Add(SQLUtility.ParameterIn("@email", SqlDbType.NVarChar, 300, email));
			da.SelectCommand.Parameters.Add(SQLUtility.ParameterIn("@phash", SqlDbType.NVarChar, 40, searchPass));
			da.Fill(result);
			ReleaseConnection();

			if (result == null) return null;
			if (result.Rows.Count < 1) return null;

			return new AdministrationUser(result.Rows[0]);
		}
		
		
		/// <summary>
		/// Saves the specified user to the database.
		/// </summary>
		/// <param name="User"></param>
		/// <returns></returns>
		public int Save(AdministrationUser User)
		{
			EstablishConnection();
			SqlCommand cmd = this.CreateSqlCommand("coreAdminUserSave");
			SqlParameter result = SQLUtility.ParameterInOut("@PK_ID", SqlDbType.Int, 4, User.PK_ID);
			cmd.Parameters.Add(result);
			cmd.Parameters.Add(SQLUtility.ParameterIn("@EmailAddress", SqlDbType.NVarChar, 300, User.EMailAddress));
			cmd.Parameters.Add(SQLUtility.ParameterIn("@NT_Username", SqlDbType.NVarChar, 200, User.NT_Username));
			cmd.Parameters.Add(SQLUtility.ParameterIn("@RealName", SqlDbType.NVarChar, 200, User.RealName));
			cmd.Parameters.Add(SQLUtility.ParameterIn("@IsSuperUser", SqlDbType.Bit, 1, User.IsSuperUser));
			cmd.ExecuteNonQuery();
			ReleaseConnection();

			if( User.PK_ID == -1 )
				User.PK_ID = (int)result.Value;

			return User.PK_ID;
		}
		
		
		/// <summary>
		/// When using Flux forms authentication, this method will set an administration
		/// user's password to the plain text password passed in. The password
		/// is first encrypted and then stored to the database.
		/// </summary>
		/// <param name="PK_ID"></param>
		/// <param name="PlainTextPassword"></param>
		public bool SetPassword(int PK_ID, string PlainTextPassword)
		{
			if (PK_ID == -1) return false;
			string hashed = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(PlainTextPassword, "sha1");

			EstablishConnection();
			SqlCommand cmd = this.CreateSqlCommand("coreAdminUserSetPassword");
			cmd.Parameters.Add(SQLUtility.ParameterIn("@id", SqlDbType.Int, 4, PK_ID));
			cmd.Parameters.Add(SQLUtility.ParameterIn("@phash", SqlDbType.NVarChar, 40, hashed));
			cmd.ExecuteNonQuery();
			ReleaseConnection();

			return true;
		}
		
		
		/// <summary>
		/// Deletes a user by it's ID.
		/// </summary>
		/// <param name="PK_ID"></param>
		/// <returns></returns>
		public bool DeleteByID(int PK_ID)
		{
			if (PK_ID == -1) return false;
			EstablishConnection();
			
			SqlCommand cmd = this.CreateSqlCommand("coreAdminUserDeleteByID");
			cmd.Parameters.Add(SQLUtility.ParameterIn("@id", SqlDbType.Int, 4, PK_ID));
			cmd.ExecuteNonQuery();

			ReleaseConnection();
			return true;
		}
		
		
		/// <summary>
		/// Sets a user's groups
		/// </summary>
		/// <param name="PK_ID"></param>
		/// <param name="groupIDs"></param>
		public void SetGroups(int PK_ID, int[] groupIDs)
		{
			try
			{
				EstablishConnection();
				BeginTransaction();

				SqlCommand ClearCmd = this.CreateSqlCommand("coreAdminUserClearGroups");
				ClearCmd.Parameters.Add(SQLUtility.ParameterIn("@userid", SqlDbType.Int, 4, PK_ID));
				ClearCmd.ExecuteNonQuery();

				foreach (int gid in groupIDs)
				{
					SqlCommand AddCmd = this.CreateSqlCommand("coreAdminUserAddGroup");
					AddCmd.Parameters.Add(SQLUtility.ParameterIn("@userid", SqlDbType.Int, 4, PK_ID));
					AddCmd.Parameters.Add(SQLUtility.ParameterIn("@groupid", SqlDbType.Int, 4, gid));
					AddCmd.ExecuteNonQuery();
				}

				EndTransaction(EndTransactionMode.COMMIT);
				ReleaseConnection();
				return;
			}
			catch (Exception e)
			{
				try { EndTransaction(EndTransactionMode.ROLLBACK); }
				catch { }
				try { ReleaseConnection(); }
				catch { }
				throw e;
			}
		}
	}
}
